/*
 * @file     GenericTraverser.cpp
 * @brief    This is the implementation of GenericTraverser interface.
 *
 * @author   Francisco Herrero
 * @email    francisco.herrero AT tallertechnologies.com
 *
 * @author   Marcos Diaz
 * @email    marcos.diaz AT tallertechnologies.com
 *
 * @author   Ocampo Emanuel
 * @email    emanuel.ocampo AT tallertechnologies.com
 * 
 *
 * Contents: Source file for traverser providing GenericTraverser implementation.
 *
 * System:   traverser
 * Language: C++
 *
 * @date September 06, 2013
 *
 * This file is part of traverser.
 *
 * traverser is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * traverser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with traverser. If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <cassert>
#include <iostream>
#include "compilerapi/GenericTree.h"
#include "traverser/GenericTraverser.h"
#include <tree-iterator.h>
#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 6)
extern "C"
{
#   include "cp/cp-tree.h"
}
#else
#   include "cp/cp-tree.h"
#endif

namespace NSGppGeneric
{

inline IGenericVisitor::AccessModifier GenericTraverser::getAccess(const NSCompilerApi::GenericTree decl)
{
    IGenericVisitor::AccessModifier ret;
    if (TREE_PRIVATE(decl))
        ret = IGenericVisitor::AccessPrivate;
    else if (TREE_PROTECTED(decl))
        ret = IGenericVisitor::AccessProtected;
    else
        ret = IGenericVisitor::AccessPublic;
    return ret;
}

const std::string GenericTraverser::RESERVED_DECLARATION = "._";

inline void GenericTraverser::getName(const NSCompilerApi::GenericTree decl, std::string& name)
{
    const NSCompilerApi::GenericTree id(DECL_NAME(decl));
    name = id ? IDENTIFIER_POINTER(id) : "<unnamed>";
}

inline bool GenericTraverser::isReservedDeclaration(const NSCompilerApi::GenericTree decl)
{
    std::string name;
    getName(decl, name);
    return (name.substr(0, 2) == RESERVED_DECLARATION);
}

inline IGenericVisitor::BinaryOperators GenericTraverser::getBinaryOperator(const NSCompilerApi::GenericTree operators)
{
    IGenericVisitor::BinaryOperators ret;

    const unsigned int treeCode = TREE_CODE(operators);
    assert(operators != NULL_TREE);
    switch(treeCode)
    {
        case MULT_EXPR:
            ret = IGenericVisitor::OP2_MULT;
        break;
        case MINUS_EXPR:
            ret = IGenericVisitor::OP2_MINUS;
        break;
        case PLUS_EXPR:
            ret = IGenericVisitor::OP2_PLUS;
        break;
        case TRUNC_DIV_EXPR:
            ret = IGenericVisitor::OP2_DIVIDE;
        break;
        default:
            ret = IGenericVisitor::OP2_OTHER;
    }
    return ret;
}

inline IGenericVisitor::AssignmentOperators GenericTraverser::getAssignmentOp(const NSCompilerApi::GenericTree assignmetOp)
{
    IGenericVisitor::AssignmentOperators ret;
    const unsigned int treeCode = TREE_CODE(assignmetOp);
    assert(assignmetOp != NULL_TREE);
    switch(treeCode)
    {
        case INIT_EXPR:
            ret = IGenericVisitor::OP_ASSIGNMENT_EQUAL;
        break;
        case MODIFY_EXPR:
            ret = IGenericVisitor::OP_ASSIGNMENT_EQUAL;
        break;
        case MINUS_EXPR:
            ret = IGenericVisitor::OP_ASSIGNMENT_EQUAL_MINUS;
        break;
        case PLUS_EXPR:
            ret = IGenericVisitor::OP_ASSIGNMENT_EQUAL_PLUS;
        break;
        default:
            ret = IGenericVisitor::OP_ASSIGNMENT_OTHER;
    }
    return ret;
}


inline void GenericTraverser::processOperands(NSCompilerApi::GenericTree body, const unsigned int operand, const unsigned int count) const
{
    for (unsigned int i = count; i < operand; ++i)
    {
        processBodyStmt(TREE_OPERAND(body,i));
    }

}

inline NSCompilerApi::GenericTree GenericTraverser::getOperandOfBody(NSCompilerApi::GenericTree body, const unsigned int operand) const
{
   return TREE_OPERAND(body,operand);
}

inline void GenericTraverser::processAddExp(NSCompilerApi::GenericTree addExpr) const
{
    assert(TREE_CODE(addExpr) == ADDR_EXPR);
    addExpr = TREE_OPERAND(addExpr,0);
    NSCompilerApi::GenericTree cc = DECL_ATTRIBUTES(addExpr);
    std::cout<<"PRINT"<<std::endl;
}

inline void GenericTraverser::processCallExp(NSCompilerApi::GenericTree callExpr) const
{
    assert(TREE_CODE(callExpr) == CALL_EXPR);
    callExpr = TREE_OPERAND(callExpr, CALL_OPERAND);
    processAddExp(callExpr);
}

inline void GenericTraverser::processDefault(NSCompilerApi::GenericTree binOp) const
{
    const unsigned int treeCode = TREE_CODE(binOp);
    if (treeCode == COMPOUND_EXPR)
    {
        NSCompilerApi::GenericTree leftValue = getOperandOfBody(binOp,LEFT_VALUE);
        NSCompilerApi::GenericTree rightValue = getOperandOfBody(binOp,RIGHT_VALUE);
        _visitor->visitAssignmentStatement(binOp, leftValue, rightValue, getAssignmentOp(binOp));
    }
    else
        // processing binary operators
    {
        NSCompilerApi::GenericTree leftOp = getOperandOfBody(binOp,LEFT_OPERATOR);
        NSCompilerApi::GenericTree rightOp = getOperandOfBody(binOp,RIGHT_OPERATOR);
        _visitor->visitBinaryOperator(binOp, leftOp, rightOp, getBinaryOperator(binOp));
    }
    processBodyStmt(TREE_OPERAND(binOp,OPERAND_DEFAULT_FIRST));
    processBodyStmt(TREE_OPERAND(binOp,OPERAND_DEFAULT_SECOND));
}

inline void GenericTraverser::processInitExpr(NSCompilerApi::GenericTree bodyIexpr) const
{

    assert(TREE_CODE(bodyIexpr) == INIT_EXPR);
    bodyIexpr = (TREE_OPERAND(bodyIexpr,INIT_EXPR_OPERAND));
    processBodyStmt(bodyIexpr);
}

inline void GenericTraverser::proccesModifyExpr(NSCompilerApi::GenericTree bodyMexpr) const
{
    assert(TREE_CODE(bodyMexpr) == MODIFY_EXPR);
    bodyMexpr = (TREE_OPERAND(bodyMexpr,MOD_EXPR_OPERAND));
    processBodyStmt(bodyMexpr);
}

inline void GenericTraverser::processConverExpr(NSCompilerApi::GenericTree convExp) const
{
    assert(TREE_CODE(convExp) == CONVERT_EXPR);
    convExp = (TREE_OPERAND(convExp,CONV_EXPR_OPERAND));
    processBodyStmt(convExp);
}

inline void GenericTraverser::processExprStmt(NSCompilerApi::GenericTree exprStmt) const
{
  assert(TREE_CODE(exprStmt) == EXPR_STMT);
  exprStmt = (TREE_OPERAND(exprStmt,EXPR_STMT_OPERAND));
  processBodyStmt(exprStmt);
}

inline void GenericTraverser::processCpExpr(NSCompilerApi::GenericTree cpExpr) const
{
   assert(TREE_CODE(cpExpr) == CLEANUP_POINT_EXPR);
   cpExpr = (TREE_OPERAND(cpExpr,CP_EXPR_OPERAND));
   processBodyStmt(cpExpr);
}

inline void GenericTraverser::processStmtList(NSCompilerApi::GenericTree stmtList) const
{
    assert(TREE_CODE(stmtList) == STATEMENT_LIST);
    for(tree_stmt_iterator i = tsi_start(stmtList); !tsi_end_p(i); tsi_next(&i))
    {
        tree stmt = tsi_stmt(i);
        processBodyStmt(stmt);
    }
}

inline void GenericTraverser::processBindExpr(NSCompilerApi::GenericTree bExpr) const
{
    assert(TREE_CODE(bExpr) == BIND_EXPR);
    bExpr = (TREE_OPERAND(bExpr,BODY_OPERAND));
    processBodyStmt(bExpr);
}

inline void GenericTraverser::processBodyIf(NSCompilerApi::GenericTree bodyIf) const
{
    assert(TREE_CODE(bodyIf) == IF_STMT);
    NSCompilerApi::GenericTree conditionIf = getOperandOfBody(bodyIf,CONDITION_IF);
    NSCompilerApi::GenericTree truePart = getOperandOfBody(bodyIf,TRUE_PART);
    NSCompilerApi::GenericTree elsePart = getOperandOfBody(bodyIf,ELSE_PART);
    _visitor->visitIfStatement(bodyIf, conditionIf, truePart, elsePart);
    processOperands(bodyIf, BOUND_IF, INITIAL_IF);
    if (elsePart != NULL_TREE)
    {
        processBodyStmt(elsePart);
    }
}

inline void GenericTraverser::processBodyWhile(NSCompilerApi::GenericTree bodyWhile) const
{
    assert(TREE_CODE(bodyWhile) == WHILE_STMT);
    NSCompilerApi::GenericTree conditionWhile = getOperandOfBody(bodyWhile, CONDITION_WHILE);
    NSCompilerApi::GenericTree body = getOperandOfBody(bodyWhile, BODY_WHILE);
    _visitor->visitWhileStatement(bodyWhile, conditionWhile, body);
    processOperands(bodyWhile, BOUND_WHILE, INITIAL_WHILE);
}

inline void GenericTraverser::processBodyFor(NSCompilerApi::GenericTree bodyFor) const
{
    assert(TREE_CODE(bodyFor) == FOR_STMT);
    NSCompilerApi::GenericTree initialization = getOperandOfBody(bodyFor, INITIALIZATION);
    NSCompilerApi::GenericTree conditionFor = getOperandOfBody(bodyFor, CONDITION_FOR);
    NSCompilerApi::GenericTree increment = getOperandOfBody(bodyFor, INCREMENT);
    NSCompilerApi::GenericTree body = getOperandOfBody(bodyFor,BODY_FOR);
    _visitor->visitForStatement(bodyFor, initialization, conditionFor, increment, body);
    processOperands(bodyFor, BOUND_FOR, INITIAL_FOR);
}

inline void GenericTraverser::processBodySwitch(NSCompilerApi::GenericTree bodySwitch) const
{
    assert(TREE_CODE(bodySwitch) == SWITCH_STMT);
    bodySwitch = TREE_OPERAND(bodySwitch,SWITCH_OPERAND);
    processBodyStmt(bodySwitch);
}

inline void GenericTraverser::proccesBodyTnexpr(NSCompilerApi::GenericTree bodyTruthNe) const
{
    bodyTruthNe = TREE_OPERAND(bodyTruthNe,TRUTH_N_EXPR_OPERAND);
    processBodyStmt(bodyTruthNe);
}

inline void GenericTraverser::processCaseLabelExpr(NSCompilerApi::GenericTree cLabelExpr) const
{
    _visitor->visitCaseLabelExpr(cLabelExpr);
}

inline void GenericTraverser::processBreakStmt(NSCompilerApi::GenericTree breakStmt) const
{
    _visitor->visitBreakStmt(breakStmt);
}

inline void GenericTraverser::processReturnExpr(NSCompilerApi::GenericTree returnExpr) const
{
    NSCompilerApi::GenericTree bodyReturnExpr = getOperandOfBody(returnExpr, BODY_RETURN_EXPR);
    if (bodyReturnExpr != NULL_TREE)
    {
        _visitor->visitReturnExpr(returnExpr, bodyReturnExpr);
        processBodyStmt(bodyReturnExpr) ;
    }
    else
    {
        _visitor->visitReturnExpr(returnExpr);
    }
}

inline void GenericTraverser::processContinueStmt(NSCompilerApi::GenericTree contStmt) const
{
   _visitor->visitContinueStmt(contStmt);
}

inline void GenericTraverser::processGotoExpr(NSCompilerApi::GenericTree gotoExpr) const
{
    NSCompilerApi::GenericTree bodyGotoExpr = getOperandOfBody(gotoExpr, LABEL_GOTO_EXPR);
    _visitor->visitGotoExpr(gotoExpr, bodyGotoExpr);
}

inline void GenericTraverser::processLabelExpr(NSCompilerApi::GenericTree lExpr) const
{
    NSCompilerApi::GenericTree bodyLabelExpr = getOperandOfBody(lExpr, BODY_OPERAND_BODY);
    processBodyStmt(bodyLabelExpr);
}

inline void GenericTraverser::processDeclExpr(NSCompilerApi::GenericTree dExpr) const
{
    NSCompilerApi::GenericTree bodyDeclExpr = getOperandOfBody(dExpr, BODY_OPERAND_BODY);
    processBodyStmt(bodyDeclExpr);
}

inline void GenericTraverser::processFloatExpr(NSCompilerApi::GenericTree fExpr) const
{
    NSCompilerApi::GenericTree bodyFexpr = getOperandOfBody(fExpr, BODY_OPERAND_BODY);
    NSCompilerApi::GenericTree typeFrom = (TREE_TYPE(fExpr));
    NSCompilerApi::GenericTree typeTo = (TREE_TYPE(bodyFexpr));
    _visitor->visitCastExpr(typeFrom, typeTo);
    processBodyStmt(bodyFexpr);
}

inline void GenericTraverser::processFixTruncExpr(NSCompilerApi::GenericTree ftExpr) const
{
    NSCompilerApi::GenericTree bodyFtExpr = getOperandOfBody(ftExpr, BODY_OPERAND_BODY);
    NSCompilerApi::GenericTree typeFrom = (TREE_TYPE(ftExpr));
    NSCompilerApi::GenericTree typeTo = (TREE_TYPE(bodyFtExpr));
    _visitor->visitCastExpr(typeFrom, typeTo);
}

inline void GenericTraverser::processNopExpr(NSCompilerApi::GenericTree nopExpr) const
{
    NSCompilerApi::GenericTree bodyNopExpr = getOperandOfBody(nopExpr, BODY_OPERAND_BODY);
    NSCompilerApi::GenericTree typeFrom = (TREE_TYPE(nopExpr));
    NSCompilerApi::GenericTree typeTo = (TREE_TYPE(bodyNopExpr));
    _visitor->visitCastExpr(typeFrom, typeTo);
    processBodyStmt(bodyNopExpr);
}

inline void GenericTraverser::processVarDecl(const NSCompilerApi::GenericTree vDecl) const
{
    processVariableDeclaration(vDecl);
}

inline void GenericTraverser::processBodyStmt(NSCompilerApi::GenericTree bodyStmt) const
{
    const unsigned int treeCode = TREE_CODE(bodyStmt);
    if (bodyStmt != NULL_TREE)
    {
        switch (treeCode)
        {
            case BIND_EXPR:
                processBindExpr(bodyStmt);
                break;
            case STATEMENT_LIST:
                processStmtList(bodyStmt);
                break;
            case CLEANUP_POINT_EXPR:
                processCpExpr(bodyStmt);
                break;
            case EXPR_STMT:
                processExprStmt(bodyStmt);
                break;
            case CONVERT_EXPR:
                processConverExpr(bodyStmt);
                break;
            case IF_STMT:
                processBodyIf(bodyStmt);
                break;
            case FOR_STMT:
                processBodyFor(bodyStmt);
                break;
            case WHILE_STMT:
                processBodyWhile(bodyStmt);
                break;
            case SWITCH_STMT:
                processBodySwitch(bodyStmt);
                break;
            case INIT_EXPR :
                processInitExpr(bodyStmt);
                break;
            case MODIFY_EXPR:
                proccesModifyExpr(bodyStmt);
                break;
            case TRUTH_NOT_EXPR:
                proccesBodyTnexpr(bodyStmt);
                break;
            case CALL_EXPR:
                processCallExp(bodyStmt);
                break;
            case VAR_DECL:
                processVarDecl(bodyStmt);
                break;
            case CASE_LABEL_EXPR:
                processCaseLabelExpr(bodyStmt);
                break;
            case DECL_EXPR:
                processDeclExpr(bodyStmt);
                break;
            case RETURN_EXPR:
                processReturnExpr(bodyStmt);
                break;
            case BREAK_STMT:
                processBreakStmt(bodyStmt);
                break;
            case CONTINUE_STMT:
                processContinueStmt(bodyStmt);
                break;
            case GOTO_EXPR:
                processGotoExpr(bodyStmt);
                break;
            case LABEL_EXPR:
                processLabelExpr(bodyStmt);
                break;
            case FLOAT_EXPR:
                processFloatExpr(bodyStmt);
                break;
            case FIX_TRUNC_EXPR:
                processFixTruncExpr(bodyStmt);
                break;
            case NOP_EXPR:
                processNopExpr(bodyStmt);
                break;
            case LABEL_DECL:
                break;
            case INTEGER_CST:
                break;
            default:
                processDefault(bodyStmt);
        }
    }
}

inline bool GenericTraverser::isConstant(const NSCompilerApi::GenericTree decl)
{
    return CP_TYPE_CONST_P(TREE_TYPE(decl));
}

inline void GenericTraverser::checkArrayTypeName(NSCompilerApi::GenericTree decl, std::string& typeName)
{
    while (TREE_CODE(TREE_TYPE(decl)) == ARRAY_TYPE)
    {
        decl = TREE_TYPE(decl);
        typeName = "_array" + typeName;
    }
}

inline void GenericTraverser::checkReferenceTypeName(NSCompilerApi::GenericTree decl, std::string& typeName)
{
    while (TREE_CODE(TREE_TYPE(decl)) == REFERENCE_TYPE)
    {
        decl = TREE_TYPE(decl);
        typeName = "_ref" + typeName;
    }
}

inline void GenericTraverser::checkPointerTypeName(NSCompilerApi::GenericTree decl, std::string& typeName)
{
    while (TREE_CODE(TREE_TYPE(decl)) == POINTER_TYPE)
    {
        decl = TREE_TYPE(decl);
        typeName = "_ptr" + typeName;
    }
}

inline void GenericTraverser::getTypeName(const NSCompilerApi::GenericTree decl, std::string& returnName)
{
    std::string typeName;
    NSCompilerApi::GenericTree aux(decl);

    checkArrayTypeName(aux, typeName);
    checkReferenceTypeName(aux, typeName);
    checkPointerTypeName(aux, typeName);

    if (TREE_CODE(TREE_TYPE(aux)) == FUNCTION_TYPE)
    {
        typeName = "func" + typeName;
    }
    else if (TYPE_NAME(TREE_TYPE(aux)) == 0)
    {
        typeName = "internal" + typeName;
    }
    else
    {
        getName(TYPE_NAME(TREE_TYPE(aux)), returnName);
    }
    returnName += typeName;
}

inline void GenericTraverser::processVariableDeclaration(const NSCompilerApi::GenericTree decl) const
{
    std::string name;
    std::string typeName;
    getName(decl, name);
    // Enum Values are Traversed in ProcessEnumValue
    if (TREE_CODE(decl) != CONST_DECL)
    {
        getTypeName(decl, typeName);
        if (TREE_CODE(CP_DECL_CONTEXT(decl)) == RECORD_TYPE)
        {
            _visitor->visitAttributeDeclaration(decl, getAccess(decl), name, isConstant(decl), typeName);
        }
        else if (TREE_CODE(CP_DECL_CONTEXT(decl)) == UNION_TYPE)
        {
            _visitor->visitUnionValueDeclaration(decl, name, isConstant(decl), typeName);
        }
        else if ((TREE_CODE(CP_DECL_CONTEXT(decl)) == NAMESPACE_DECL)&& isConstant(decl))
        {
            _visitor->visitGlobalConstDeclaration(decl, name);
        }
        else
        {
            _visitor->visitVariableDeclaration(decl, name, isConstant(decl), typeName);
        }
    }
}

inline void GenericTraverser::processTemplateDeclaration(const NSCompilerApi::GenericTree decl) const
{
    processDeclaration(DECL_TEMPLATE_RESULT(decl));

    NSCompilerApi::GenericTree templateparms(TREE_VALUE(DECL_TEMPLATE_PARMS(decl)));
    for (size_t i(0); i < size_t(TREE_VEC_LENGTH(templateparms)); ++i)
    {
        processDeclaration(TREE_VALUE(TREE_VEC_ELT(templateparms, i)));
    }

}

 inline void GenericTraverser::processMethods(const NSCompilerApi::GenericTree type) const
{
    for (NSCompilerApi::GenericTree d(TYPE_METHODS(type)); d != 0; d = TREE_CHAIN(d))
    {
        if (!DECL_ARTIFICIAL(d))
        {
            processDeclaration(d);
        }
    }
}

inline void GenericTraverser::processAttributes(const NSCompilerApi::GenericTree type) const
{
    for (NSCompilerApi::GenericTree d(TYPE_FIELDS(type)); d != 0; d = TREE_CHAIN(d))
    {
        /*one of the nodes in TYPE_FIELDS is the self reference*/
        if (!DECL_SELF_REFERENCE_P(d))
            processDeclaration(d);
    }
}

inline void GenericTraverser::processRecordDeclaration(const NSCompilerApi::GenericTree decl) const
{
    std::string name;
    getName(decl, name);
    if (CLASSTYPE_DECLARED_CLASS(TREE_TYPE(decl)))
        _visitor->visitClassDeclaration(decl, name);
    else
        _visitor->visitStructDeclaration(decl, name);
}

inline void GenericTraverser::unionOrRecord(const NSCompilerApi::GenericTree decl, const NSCompilerApi::GenericTree type, std::string& name) const
{
    if (TREE_CODE(type) == RECORD_TYPE)
    {
        processRecordDeclaration(decl);
    }
    else if (TREE_CODE(type) == UNION_TYPE)
    {
        _visitor->visitUnionDeclaration(decl, name);
    }
}

inline void GenericTraverser::processTypeDeclArtificial(const NSCompilerApi::GenericTree decl) const
{
    assert((TREE_CODE(decl) == TYPE_DECL) && DECL_ARTIFICIAL(decl));

    NSCompilerApi::GenericTree type(TREE_TYPE(decl));
    std::string name;
    getName(decl, name);

    unionOrRecord(decl, type, name);

    if (TREE_CODE(type) == TEMPLATE_TYPE_PARM || TREE_CODE(type) == TEMPLATE_TEMPLATE_PARM)
    {
        if (name != "<unnamed>")
        {
            _visitor->visitTemplateTypeParameterDeclaration(decl, name);
        }
    }
    else
    {
        processAttributes(type);

        processMethods(type);
    }
}

inline void GenericTraverser::processEnumValues(const NSCompilerApi::GenericTree decl) const
{
    std::string name;
    for (NSCompilerApi::GenericTree d(TYPE_VALUES(TREE_TYPE(decl))); d != 0; d = TREE_CHAIN(d))
    {
        getName(TREE_VALUE(d), name);
        _visitor->visitEnumValueDeclaration(TREE_VALUE(d), name);
    }
}

inline void GenericTraverser::processEnumType(const NSCompilerApi::GenericTree decl) const
{
    std::string name;
    getName(decl, name);
    if (DECL_ARTIFICIAL(decl))
        _visitor->visitEnumTypeDeclaration(decl, name);
    else
        _visitor->visitTypeDeclaration(decl, name);
    processEnumValues(decl);
}

inline void GenericTraverser::processType(const NSCompilerApi::GenericTree decl) const
{
    assert(TREE_CODE(decl) == TYPE_DECL);
    std::string name;
    getName(decl, name);
    if (!isReservedDeclaration(decl))
    {
        if (TREE_CODE(TREE_TYPE(decl)) == ENUMERAL_TYPE)
        {
            processEnumType(decl);
        }
        else if (DECL_ARTIFICIAL(decl))
        {
            processTypeDeclArtificial(decl);
        }
        else
        {
            _visitor->visitTypeDeclaration(decl, name);
        }
    }
}

inline void GenericTraverser::processSubblocks(const NSCompilerApi::GenericTree block) const
{
    NSCompilerApi::GenericTree subblocks(BLOCK_SUBBLOCKS(block));
    if (subblocks != NULL_TREE)
    {
        processBlock(subblocks);
    }
}

inline void GenericTraverser::processBlockVariables(const NSCompilerApi::GenericTree block) const
{
    for (NSCompilerApi::GenericTree d(BLOCK_VARS(block)); d != 0; d = TREE_CHAIN(d))
    {
        processDeclaration(d);
    }
}

inline void GenericTraverser::processBlock(const NSCompilerApi::GenericTree decl) const
{
    assert(TREE_CODE(decl) == BLOCK);
    for (NSCompilerApi::GenericTree block(decl); block != 0; block = BLOCK_CHAIN(block))
    {
        processBlockVariables(block);

        processSubblocks(block);
    }
}

inline void GenericTraverser::functionOrMethod(const NSCompilerApi::GenericTree decl, std::string& name) const
{
    if (TREE_CODE(TREE_TYPE(decl)) == METHOD_TYPE)
    {
        if (!DECL_COPY_CONSTRUCTOR_P(decl)
                && !DECL_CONSTRUCTOR_P(decl)
                && !DECL_DESTRUCTOR_P(decl)
                && !DECL_OVERLOADED_OPERATOR_P(decl)
                && !DECL_CONV_FN_P(decl))
        {
            _visitor->visitMethodDeclaration(decl, getAccess(decl), name, isConstant(decl));
        }
    }
    else
        _visitor->visitFunctionDeclaration(decl, name);

}

inline void GenericTraverser::processFunctionBody(const NSCompilerApi::GenericTree decl) const
{
    const NSCompilerApi::GenericTree declInitial = DECL_INITIAL(decl);
    if (declInitial != NULL_TREE && TREE_CODE(declInitial) != ERROR_MARK)
        processBlock(declInitial);
}

inline void GenericTraverser::processParameters(const NSCompilerApi::GenericTree decl) const
{
    std::string name;
    getName(decl, name);
    for (NSCompilerApi::GenericTree d(DECL_ARGUMENTS(decl)); d != 0; d = TREE_CHAIN(d))
    {
        getName(d, name);
        if (!DECL_SELF_REFERENCE_P(d)
                && (name != "<unnamed>")
                && (name != "this")
                && (name != "__in_chrg"))
        {
            _visitor->visitParameterDeclaration(d, name, isConstant(d));
        }
    }
}

inline void GenericTraverser::processFunctionStmt(const NSCompilerApi::GenericTree funcStmt) const
{
    NSCompilerApi::GenericTree functBody = DECL_SAVED_TREE(funcStmt); 
    processBodyStmt(functBody);
}

inline void GenericTraverser::processFunction(const NSCompilerApi::GenericTree decl) const
{
    assert(TREE_CODE(decl) == FUNCTION_DECL);
    std::string name;
    getName(decl, name);
    if (name != "__static_initialization_and_destruction_0")
    {
        processFunctionStmt(decl);
        functionOrMethod(decl, name);
        processParameters(decl);
        processFunctionBody(decl);
    }

}

inline void GenericTraverser::processDeclaration(const NSCompilerApi::GenericTree decl) const
{
    if (!DECL_IS_BUILTIN(decl))
    {
        const int treeCode = TREE_CODE(decl);

        if (treeCode == FUNCTION_DECL)
        {
            processFunction(decl);
        }
        else if (treeCode == TYPE_DECL)
        {
            processType(decl);
        }
        else if (treeCode == TEMPLATE_DECL)
        {
            processTemplateDeclaration(decl);
        }
        else if (treeCode == BLOCK)
        {
            processBlock(decl);
        }
        else if (!DECL_ARTIFICIAL(decl))
        {
            processVariableDeclaration(decl);
        }
    }
}

inline void GenericTraverser::traverseDeclarations(const NSCompilerApi::GenericTree ns) const
{
    const cp_binding_level* level(NAMESPACE_LEVEL(ns));
    for (NSCompilerApi::GenericTree decl(level->names); decl != 0; decl = TREE_CHAIN(decl))
    {
        processDeclaration(decl);
    }
}

inline void GenericTraverser::traverseNamespaces(const NSCompilerApi::GenericTree ns) const
{
    const cp_binding_level* const level(NAMESPACE_LEVEL(ns));
    for (NSCompilerApi::GenericTree decl = level->namespaces; decl != 0; decl = TREE_CHAIN(decl))
    {
        std::string namespaceName;
        getName(decl, namespaceName);
        if (!DECL_IS_BUILTIN(decl) && namespaceName != "std")
        {
            _visitor->visitNamespaceDeclaration(decl, namespaceName);
            traverse(decl);
        }
    }
}

void GenericTraverser::traverse(const NSCompilerApi::GenericTree ns) const
{
    // Traverse declarations.
    traverseDeclarations(ns);

    // Traverse namespaces.
    traverseNamespaces(ns);
}

} // end namespace
